package com.ala4.oxcafe.boot.interceptor;

import com.ala4.oxcafe.common.utils.object.ObjectUtil;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
import com.baomidou.mybatisplus.extension.parser.JsqlParserSupport;
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.StringValue;
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
import net.sf.jsqlparser.expression.operators.relational.EqualsTo;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.schema.Table;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.select.FromItem;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.Select;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

import java.sql.SQLException;

/**
 * @author PING
 * @date 2025/3/22 23:53
 */
@Slf4j
public class LogicDeleteWhereInnerInterceptor extends JsqlParserSupport implements InnerInterceptor {

    @Override
    public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
        // 查询才执行
        if (SqlCommandType.SELECT != ms.getSqlCommandType()) {
            return;
        }
        // 解析boundSql
        String origSql = boundSql.getSql();

        PlainSelect plainSelect = null;
        Table table = null;
        try {
            Statement statement = CCJSqlParserUtil.parse(origSql);
            if (statement instanceof Select select) {
                plainSelect = select.getPlainSelect();
                // 只获取主表
                FromItem fromItem = plainSelect.getFromItem();
                if (fromItem instanceof Table fromTable) {
                    table = fromTable;
                }
            }
        } catch (Exception exception) {
            log.error("添加逻辑删除字段解析SQL失败", exception);
        }
        if (ObjectUtil.isNull(table)) {
            log.warn("嵌套查询SQL,无法自动添加逻辑删除字段,请确认是否添加逻辑删除字段[{}]", origSql);
            return;
        }
        TableInfo tableInfo = TableInfoHelper.getTableInfo(table.getName());
        if (ObjectUtil.isNull(tableInfo) || !tableInfo.isWithLogicDelete()) {
            return;
        }

        // 3. 获取逻辑删除配置
        String logicDeleteColumn = tableInfo.getLogicDeleteFieldInfo().getColumn();
        String logicDeleteValue = tableInfo.getLogicDeleteFieldInfo().getLogicNotDeleteValue();

        // 4. 解析并修改SQL
        boolean processSuccessful = processSelect(plainSelect, table, logicDeleteColumn, logicDeleteValue);

        // 5. 如果解析并且修改成功设置回去
        if (processSuccessful) {
            // 修改完成的sql 再设置回去
            PluginUtils.MPBoundSql mpBoundSql = PluginUtils.mpBoundSql(boundSql);
            mpBoundSql.sql(plainSelect.toString());
        }
    }

    // 以下处理方法与旧版逻辑类似，但适配最新JSqlParser API
    private boolean processSelect(Select select, Table table, String column, String value) {
        PlainSelect plainSelect = select.getPlainSelect();
        Expression where = plainSelect.getWhere();
        // 判断where条件里面是否包含了逻辑伤处字段 如果已经包含了就不用添加了
        if (containsCondition(where, column)) {
            return false;
        }

        plainSelect.setWhere(buildNewWhere(where, createLogicExpr(table, column, value)));
        return true;
    }

    private boolean containsCondition(Expression where, String column) {
        if (where == null) return false;
        return where.toString().contains(column);
    }

    private Expression buildNewWhere(Expression origin, Expression append) {
        return origin == null ? append : new AndExpression(origin, append);
    }

    private EqualsTo createLogicExpr(Table table, String column, String value) {
        EqualsTo expr = new EqualsTo();
        expr.setLeftExpression(new Column(table, column));
        expr.setRightExpression(new StringValue(value)); // 支持字符串类型值
        return expr;
    }
}
